home *** CD-ROM | disk | FTP | other *** search
/ X User Tools / X User Tools (O'Reilly and Associates)(1994).ISO / sources / xfontsel / xfontsel.c < prev    next >
C/C++ Source or Header  |  1994-09-27  |  36KB  |  1,423 lines

  1. /* $XConsortium: xfontsel.c,v 1.33 91/06/22 21:33:52 rws Exp $
  2.  
  3. Copyright 1985, 1986, 1987, 1988, 1989 by the
  4. Massachusetts Institute of Technology
  5.  
  6. Permission to use, copy, modify, and distribute this
  7. software and its documentation for any purpose and without
  8. fee is hereby granted, provided that the above copyright
  9. notice appear in all copies and that both that copyright
  10. notice and this permission notice appear in supporting
  11. documentation, and that the name of M.I.T. not be used in
  12. advertising or publicity pertaining to distribution of the
  13. software without specific, written prior permission.
  14. M.I.T. makes no representations about the suitability of
  15. this software for any purpose.  It is provided "as is"
  16. without express or implied warranty.
  17.  
  18. Author:    Ralph R. Swick, DEC/MIT Project Athena
  19.     one weekend in November, 1989
  20. */
  21.  
  22. #include <stdio.h>
  23. #include <X11/Intrinsic.h>
  24. #include <X11/StringDefs.h>
  25. #include <X11/Xatom.h>
  26. #include <X11/Xaw/AsciiText.h>
  27. #include <X11/Xaw/Box.h>
  28. #include <X11/Xaw/Cardinals.h>
  29. #include <X11/Xaw/Command.h>
  30. #include <X11/Xaw/Form.h>
  31. #include <X11/Xaw/MenuButton.h>
  32. #include <X11/Xaw/Paned.h>
  33. #include <X11/Xaw/SimpleMenu.h>
  34. #include <X11/Xaw/SmeBSB.h>
  35. #include <X11/Xaw/Toggle.h>
  36. #include <X11/Xaw/Viewport.h>
  37. #include <X11/Xmu/Atoms.h>
  38. #include <X11/Xmu/StdSel.h>
  39. #include <X11/Xfuncs.h>
  40.  
  41. #define MIN_APP_DEFAULTS_VERSION 1
  42. #define FIELD_COUNT 14
  43. #define DELIM '-'
  44.  
  45. /* number of font names to parse in each background iteration */
  46. #ifndef PARSE_QUANTUM
  47. #define PARSE_QUANTUM 25
  48. #endif
  49.  
  50. #define NZ NULL,ZERO
  51. #define BACKGROUND 10
  52.  
  53. void GetFontNames();
  54. Boolean Matches();
  55. Boolean DoWorkPiece();
  56. void Quit();
  57. void OwnSelection();
  58. void SelectField();
  59. void ParseFontNames();
  60. void SortFields();
  61. void FixScalables();
  62. void MakeFieldMenu();
  63. void SelectValue();
  64. void AnyValue();
  65. void EnableOtherValues();
  66. void EnableMenu();
  67. void SetCurrentFont();
  68. void QuitAction();
  69.  
  70. XtActionsRec xfontsel_actions[] = {
  71.     "Quit",        QuitAction
  72. };
  73.  
  74. Atom wm_delete_window;
  75.  
  76. Boolean IsXLFDFontName();
  77.  
  78. typedef void (*XtProc)();
  79.  
  80. static struct _appRes {
  81.     int app_defaults_version;
  82.     Cursor cursor;
  83.     String pattern;
  84.     String pixelSizeList;
  85.     String pointSizeList;
  86.     Boolean print_on_quit;
  87.     String sample_text;
  88.     String sample_text16;
  89.     Boolean scaled_fonts;
  90. } AppRes;
  91.  
  92. #define DEFAULTPATTERN "-*-*-*-*-*-*-*-*-*-*-*-*-*-*"
  93.  
  94. static XtResource resources[] = {
  95.     { "cursor", "Cursor", XtRCursor, sizeof(Cursor),
  96.         XtOffsetOf( struct _appRes, cursor ),
  97.         XtRImmediate, NULL },
  98.     { "pattern", "Pattern", XtRString, sizeof(String),
  99.         XtOffsetOf( struct _appRes, pattern ),
  100.         XtRString, (XtPointer)DEFAULTPATTERN },
  101.     { "pixelSizeList", "PixelSizeList", XtRString, sizeof(String),
  102.                 XtOffsetOf( struct _appRes, pixelSizeList ),
  103.                 XtRString, (XtPointer)"" },
  104.     { "pointSizeList", "PointSizeList", XtRString, sizeof(String),
  105.                 XtOffsetOf( struct _appRes, pointSizeList ),
  106.                 XtRString, (XtPointer)"" },
  107.     { "printOnQuit", "PrintOnQuit", XtRBoolean, sizeof(Boolean),
  108.           XtOffsetOf( struct _appRes, print_on_quit ),
  109.               XtRImmediate, (XtPointer)False },
  110.     { "appDefaultsVersion", "AppDefaultsVersion", XtRInt, sizeof(int),
  111.         XtOffsetOf( struct _appRes, app_defaults_version ),
  112.         XtRImmediate, (XtPointer)0 },
  113.     { "sampleText", "Text", XtRString, sizeof(String),
  114.         XtOffsetOf( struct _appRes, sample_text ),
  115.         XtRString, (XtPointer)"" },
  116.     { "sampleText16", "Text16", XtRString, sizeof(String),
  117.         XtOffsetOf( struct _appRes, sample_text16 ),
  118.         XtRString, (XtPointer)"" },
  119.     { "scaledFonts", "ScaledFonts", XtRBoolean, sizeof(Boolean),
  120.           XtOffsetOf( struct _appRes, scaled_fonts ),
  121.               XtRImmediate, (XtPointer)True },
  122. };
  123.  
  124. static XrmOptionDescRec options[] = {
  125. {"-pattern",    "pattern",    XrmoptionSepArg,    NULL},
  126. {"-print",    "printOnQuit",    XrmoptionNoArg,        "True"},
  127. {"-sample",    "sampleText",    XrmoptionSepArg,    NULL},
  128. {"-sample16",    "sampleText16",    XrmoptionSepArg,    NULL},
  129. {"-noscaled",    "scaledFonts",    XrmoptionNoArg,        "False"},
  130. };
  131.  
  132. Syntax(call)
  133.     char *call;
  134. {
  135.     fprintf (stderr, "usage:  %s [-options ...] -fn font\n\n", call);
  136.     fprintf (stderr, "where options include:\n");
  137.     fprintf (stderr,
  138.     "    -display dpy           X server to contact\n");
  139.     fprintf (stderr, 
  140.     "    -geometry geom         size and location of window\n");
  141.     fprintf (stderr, 
  142.     "    -pattern fontspec      font name pattern to match against\n");
  143.     fprintf (stderr, 
  144.     "    -print                 print selected font name on exit\n");
  145.     fprintf (stderr, 
  146.     "    -noscaled              do not use scaled instances of fonts\n");
  147.     fprintf (stderr, 
  148.     "    -sample string         sample text to use for 1-byte fonts\n");
  149.     fprintf (stderr, 
  150.     "    -sample16 string       sample text to use for 2-byte fonts\n");
  151.     fprintf (stderr, "\n");
  152.     exit (1);
  153. }
  154.  
  155.  
  156. typedef struct FieldValue FieldValue;
  157. struct FieldValue {
  158.     int field;
  159.     String string;
  160.     Widget menu_item;
  161.     int count;            /* of fonts */
  162.     int allocated;
  163.     int *font;
  164.     Boolean enable;
  165. };
  166.  
  167.  
  168. typedef struct FieldValueList FieldValueList;
  169. struct FieldValueList {
  170.     int count;            /* of values */
  171.     int allocated;
  172.     Boolean show_unselectable;
  173.     FieldValue value[1];    /* really [allocated] */
  174. };
  175.  
  176.  
  177. typedef struct FontValues FontValues;
  178. struct FontValues {
  179.     int value_index[FIELD_COUNT];
  180. };
  181.  
  182.  
  183. typedef struct FieldMenuRec FieldMenuRec;
  184. struct FieldMenuRec {
  185.     int field;
  186.     Widget button;
  187. };
  188.  
  189.  
  190. typedef struct Choice Choice;
  191. struct Choice {
  192.     Choice *prev;
  193.     FieldValue *value;
  194. };
  195.  
  196.  
  197. static XtResource menuResources[] = {
  198.     { "showUnselectable", "ShowUnselectable", XtRBoolean, sizeof(Boolean),
  199.         XtOffsetOf( FieldValueList, show_unselectable ),
  200.         XtRImmediate, (XtPointer)True },
  201. };
  202.  
  203.  
  204. typedef enum {ValidateCurrentField, SkipCurrentField} ValidateAction;
  205.  
  206. XtAppContext appCtx;
  207. int numFonts;
  208. int numBadFonts;
  209. FontValues *fonts;
  210. int *scaledFonts;
  211. int numScaledFonts;
  212. FieldValueList *fieldValues[FIELD_COUNT];
  213. FontValues currentFont;
  214. int matchingFontCount;
  215. static Boolean anyDisabled = False;
  216. Widget ownButton;
  217. Widget fieldBox;
  218. Widget countLabel;
  219. Widget currentFontName;
  220. String currentFontNameString;
  221. int currentFontNameSize;
  222. Widget sampleText;
  223. int textEncoding = -1;
  224. static XFontStruct *sampleFont = NULL;
  225. Boolean *fontInSet;
  226. static Choice *choiceList = NULL;
  227. int enabledMenuIndex;
  228. static Boolean patternFieldSpecified[FIELD_COUNT]; /* = 0 */
  229.  
  230.  
  231. void main(argc, argv)
  232.     int argc;
  233.     char **argv;
  234. {
  235.     Widget topLevel, pane;
  236.  
  237.     topLevel = XtAppInitialize(&appCtx, "XFontSel", options, XtNumber(options),
  238.                    &argc, argv, NULL, NULL, 0);
  239.  
  240.     if (argc != 1) Syntax(argv[0]);
  241.  
  242.     XtAppAddActions(appCtx, xfontsel_actions, XtNumber(xfontsel_actions));
  243.     XtOverrideTranslations
  244.     (topLevel, XtParseTranslationTable ("<Message>WM_PROTOCOLS: Quit()"));
  245.  
  246.     XtGetApplicationResources( topLevel, (XtPointer)&AppRes,
  247.                    resources, XtNumber(resources), NZ );
  248.     if (AppRes.app_defaults_version < MIN_APP_DEFAULTS_VERSION) {
  249.     XrmDatabase rdb = XtDatabase(XtDisplay(topLevel));
  250.     XtWarning( "app-defaults file not properly installed." );
  251.     XrmPutLineResource( &rdb,
  252. "*sampleText*Label:XFontSel app-defaults file not properly installed;\\n\
  253. see 'xfontsel' manual page."
  254.               );
  255.     }
  256.  
  257.     ScheduleWork(GetFontNames, (XtPointer)XtDisplay(topLevel), 0);
  258.  
  259.     pane = XtCreateManagedWidget("pane",panedWidgetClass,topLevel,NZ);
  260.     {
  261.     Widget commandBox, /* fieldBox, currentFontName,*/ viewPort;
  262.  
  263.     commandBox = XtCreateManagedWidget("commandBox",formWidgetClass,pane,NZ);
  264.     {
  265.         Widget quitButton /*, ownButton , countLabel*/;
  266.  
  267.         quitButton =
  268.         XtCreateManagedWidget("quitButton",commandWidgetClass,commandBox,NZ);
  269.  
  270.         ownButton =
  271.         XtCreateManagedWidget("ownButton",toggleWidgetClass,commandBox,NZ);
  272.  
  273.         countLabel =
  274.         XtCreateManagedWidget("countLabel",labelWidgetClass,commandBox,NZ);
  275.  
  276.         XtAddCallback(quitButton, XtNcallback, Quit, NULL);
  277.         XtAddCallback(ownButton,XtNcallback,OwnSelection,(XtPointer)True);
  278.     }
  279.  
  280.     fieldBox = XtCreateManagedWidget("fieldBox", boxWidgetClass, pane, NZ);
  281.     {
  282.         Widget /*dash,*/ field /*[FIELD_COUNT]*/;
  283.         int f;
  284.  
  285.         for (f = 0; f < FIELD_COUNT; f++) {
  286.         char name[10];
  287.         FieldMenuRec *makeRec = XtNew(FieldMenuRec);
  288.         sprintf( name, "field%d", f );
  289.         XtCreateManagedWidget("dash",labelWidgetClass,fieldBox,NZ);
  290.         field = XtCreateManagedWidget(name,menuButtonWidgetClass,fieldBox,NZ);
  291.         XtAddCallback(field, XtNcallback, SelectField, (XtPointer)f);
  292.         makeRec->field = f;
  293.         makeRec->button = field;
  294.         ScheduleWork(MakeFieldMenu, (XtPointer)makeRec, 2);
  295.         ScheduleWork(XtFree, (XtPointer)makeRec, 2);
  296.         }
  297.     }
  298.  
  299.     /* currentFontName = */
  300.     {
  301.         Arg args[1];
  302.         currentFontNameSize = strlen(AppRes.pattern);
  303.         if (currentFontNameSize < 128) currentFontNameSize = 128;
  304.         currentFontNameString = (String)XtMalloc(currentFontNameSize);
  305.         strcpy(currentFontNameString, AppRes.pattern);
  306.         XtSetArg(args[0], XtNlabel, currentFontNameString);
  307.         currentFontName =
  308.         XtCreateManagedWidget("fontName",labelWidgetClass,pane,args,ONE);
  309.     }
  310.  
  311.     viewPort =
  312.         XtCreateManagedWidget("viewPort",viewportWidgetClass,pane,NZ);
  313.     {
  314. #ifdef USE_TEXT_WIDGET
  315.         Widget text =
  316.         XtCreateManagedWidget("sampleText",asciiTextWidgetClass,viewPort,NZ);
  317.         Arg args[1];
  318.         XtSetArg( args[0], XtNtextSink, &sampleText );
  319.         XtGetValues( text, args, ONE );
  320. #else
  321.         sampleText =
  322.         XtCreateManagedWidget("sampleText",labelWidgetClass,viewPort,NZ);
  323. #endif
  324.     }
  325.     }
  326.     
  327.     XtRealizeWidget(topLevel);
  328.     XDefineCursor( XtDisplay(topLevel), XtWindow(topLevel), AppRes.cursor );
  329.     {
  330.     int f;
  331.     for (f = 0; f < FIELD_COUNT; f++) currentFont.value_index[f] = -1;
  332.     }
  333.     wm_delete_window = XInternAtom(XtDisplay(topLevel), "WM_DELETE_WINDOW",
  334.                    False);
  335.     (void) XSetWMProtocols (XtDisplay(topLevel), XtWindow(topLevel),
  336.                             &wm_delete_window, 1);
  337.     XtAppMainLoop(appCtx);
  338. }
  339.  
  340.  
  341. typedef struct WorkPiece WorkPieceRec, *WorkPiece;
  342. struct WorkPiece {
  343.     WorkPiece next;
  344.     int priority;
  345.     XtProc proc;
  346.     XtPointer closure;
  347. };
  348. static WorkPiece workQueue = NULL;
  349.  
  350.  
  351. /*
  352.  * ScheduleWork( XtProc proc, XtPointer closure, int priority )
  353.  *
  354.  * Adds a WorkPiece to the workQueue in FIFO order by priority.
  355.  * Lower numbered priority work is completed before higher numbered
  356.  * priorities.
  357.  *
  358.  * If the workQueue was previously empty, then makes sure that
  359.  * Xt knows we have (background) work to do.
  360.  */
  361.  
  362.  
  363. ScheduleWork( proc, closure, priority )
  364.     XtProc proc;
  365.     XtPointer closure;
  366.     int priority;
  367. {
  368.     WorkPiece piece = XtNew(WorkPieceRec);
  369.  
  370.     piece->priority = priority;
  371.     piece->proc = proc;
  372.     piece->closure = closure;
  373.     if (workQueue == NULL) {
  374.     piece->next = NULL;
  375.     workQueue = piece;
  376.     XtAppAddWorkProc(appCtx, DoWorkPiece, NULL);
  377.     } else {
  378.     if (workQueue->priority > priority) {
  379.         piece->next = workQueue;
  380.         workQueue = piece;
  381.     }
  382.     else {
  383.         WorkPiece n;
  384.         for (n = workQueue; n->next && n->next->priority <= priority;)
  385.         n = n->next;
  386.         piece->next = n->next;
  387.         n->next = piece;
  388.     }
  389.     }
  390. }
  391.  
  392. /* ARGSUSED */
  393. Boolean DoWorkPiece(closure)
  394.     XtPointer closure;        /* unused */
  395. {
  396.     WorkPiece piece = workQueue;
  397.  
  398.     if (piece) {
  399.     (*piece->proc)(piece->closure);
  400.     workQueue = piece->next;
  401.     XtFree((XtPointer)piece);
  402.     if (workQueue != NULL)
  403.         return False;
  404.     }
  405.     return True;
  406. }
  407.  
  408.  
  409. /*
  410.  * FinishWork()
  411.  *
  412.  * Drains foreground tasks from the workQueue.
  413.  * Foreground == (priority < BACKGROUND)
  414.  */
  415.  
  416. void FinishWork()
  417. {
  418.     while (workQueue && workQueue->priority < BACKGROUND)
  419.     DoWorkPiece(NULL);
  420. }
  421.  
  422.  
  423. typedef struct ParseRec ParseRec;
  424. struct ParseRec {
  425.     char **fontNames;
  426.     int num_fonts;
  427.     int start, end;
  428.     FontValues *fonts;
  429.     FieldValueList **fieldValues;
  430. };
  431.  
  432.  
  433. void GetFontNames( closure )
  434.     XtPointer closure;
  435. {
  436.     Display *dpy = (Display*)closure;
  437.     ParseRec *parseRec = XtNew(ParseRec);
  438.     int f, field, count;
  439.     String *fontNames;
  440.     Boolean *b;
  441.     int work_priority = 0;
  442.  
  443.     fontNames = parseRec->fontNames =
  444.     XListFonts(dpy, AppRes.pattern, 32767, &numFonts);
  445.  
  446.     fonts = (FontValues*)XtMalloc( numFonts*sizeof(FontValues) );
  447.     fontInSet = (Boolean*)XtMalloc( numFonts*sizeof(Boolean) );
  448.     for (f = numFonts, b = fontInSet; f; f--, b++) *b = True;
  449.     for (field = 0; field < FIELD_COUNT; field++) {
  450.     fieldValues[field] = (FieldValueList*)XtMalloc(sizeof(FieldValueList));
  451.     fieldValues[field]->allocated = 1;
  452.     fieldValues[field]->count = 0;
  453.     }
  454.     if (numFonts == 0) {
  455.     SetNoFonts();
  456.     return;
  457.     }
  458.     numBadFonts = 0;
  459.     parseRec->fonts = fonts;
  460.     parseRec->num_fonts = count = matchingFontCount = numFonts;
  461.     parseRec->fieldValues = fieldValues;
  462.     parseRec->start = 0;
  463.     /* this is bogus; the task should be responsible for quantizing...*/
  464.     while (count > PARSE_QUANTUM) {
  465.     ParseRec *prevRec = parseRec;
  466.     parseRec->end = parseRec->start + PARSE_QUANTUM;
  467.     ScheduleWork(ParseFontNames, (XtPointer)parseRec, work_priority);
  468.     ScheduleWork(XtFree, (XtPointer)parseRec, work_priority);
  469.     parseRec = XtNew(ParseRec);
  470.     *parseRec = *prevRec;
  471.     parseRec->start += PARSE_QUANTUM;
  472.     parseRec->fonts += PARSE_QUANTUM;
  473.     parseRec->fontNames += PARSE_QUANTUM;
  474.     count -= PARSE_QUANTUM;
  475.     work_priority = 1;
  476.     }
  477.     parseRec->end = numFonts;
  478.     ScheduleWork(ParseFontNames,(XtPointer)parseRec,work_priority);
  479.     ScheduleWork((XtProc)XFreeFontNames,(XtPointer)fontNames,work_priority);
  480.     ScheduleWork(XtFree, (XtPointer)parseRec, work_priority);
  481.     if (AppRes.scaled_fonts)
  482.     ScheduleWork(FixScalables,(XtPointer)0,work_priority);
  483.     ScheduleWork(SortFields,(XtPointer)0,work_priority);
  484.     SetParsingFontCount(matchingFontCount);
  485.     if (strcmp(AppRes.pattern, DEFAULTPATTERN)) {
  486.     int maxField, f;
  487.     for (f = 0; f < numFonts && !IsXLFDFontName(fontNames[f]); f++);
  488.     if (f != numFonts) {
  489.         if (Matches(AppRes.pattern, fontNames[f],
  490.              patternFieldSpecified, &maxField)) {
  491.         for (f = 0; f <= maxField; f++) {
  492.             if (patternFieldSpecified[f])
  493.             currentFont.value_index[f] = 0;
  494.         }
  495.         }
  496.         else
  497.         XtAppWarning( appCtx, 
  498.             "internal error; pattern didn't match first font" );
  499.     }
  500.     else {
  501.         SetNoFonts();
  502.         return;
  503.     }
  504.     }
  505.     ScheduleWork(SetCurrentFont, NULL, 1);
  506. }
  507.  
  508.  
  509. void ParseFontNames( closure )
  510.     XtPointer closure;
  511. {
  512.     ParseRec *parseRec = (ParseRec*)closure;
  513.     char **fontNames = parseRec->fontNames;
  514.     int num_fonts = parseRec->end;
  515.     FieldValueList **fieldValues = parseRec->fieldValues;
  516.     FontValues *fontValues = parseRec->fonts - numBadFonts;
  517.     int i, font;
  518.  
  519.     for (font = parseRec->start; font < num_fonts; font++) {
  520.         char *p;
  521.         int f, len;
  522.         FieldValue *v;
  523.  
  524.     if (!IsXLFDFontName(*fontNames)) {
  525.         numFonts--;
  526.         numBadFonts++;
  527.         continue;
  528.     }
  529.  
  530.     for (f = 0, p = *fontNames++; f < FIELD_COUNT; f++) {
  531.         char *fieldP;
  532.  
  533.         if (*p) ++p;
  534.         if (*p == DELIM || *p == '\0') {
  535.         fieldP = "";
  536.         len = 0;
  537.         } else {
  538.         fieldP = p;
  539.         while (*p && *++p != DELIM);
  540.         len = p - fieldP;
  541.         }
  542.         for (i=fieldValues[f]->count,v=fieldValues[f]->value; i;i--,v++) {
  543.         if (len == 0) {
  544.             if (v->string == NULL) break;
  545.         }
  546.         else
  547.             if (v->string &&
  548.             strncmp( v->string, fieldP, len ) == 0 &&
  549.             (v->string)[len] == '\0')
  550.             break;
  551.         }
  552.         if (i == 0) {
  553.         int count = fieldValues[f]->count++;
  554.         if (count == fieldValues[f]->allocated) {
  555.             int allocated = (fieldValues[f]->allocated += 10);
  556.             fieldValues[f] = (FieldValueList*)
  557.             XtRealloc( (char *) fieldValues[f],
  558.                    sizeof(FieldValueList) +
  559.                     (allocated-1) * sizeof(FieldValue) );
  560.         }
  561.         v = &fieldValues[f]->value[count];
  562.         v->field = f;
  563.         if (len == 0)
  564.             v->string = NULL;
  565.         else {
  566.             v->string = (String)XtMalloc( len+1 );
  567.             strncpy( v->string, fieldP, len );
  568.             v->string[len] = '\0';
  569.         }
  570.         v->font = (int*)XtMalloc( 10*sizeof(int) );
  571.         v->allocated = 10;
  572.         v->count = 0;
  573.         v->enable = True;
  574.         i = 1;
  575.         }
  576.         fontValues->value_index[f] = fieldValues[f]->count - i;
  577.         if ((i = v->count++) == v->allocated) {
  578.         int allocated = (v->allocated += 10);
  579.         v->font = (int*)XtRealloc( (char *) v->font, 
  580.                       allocated * sizeof(int) );
  581.         }
  582.         v->font[i] = font - numBadFonts;
  583.     }
  584.     fontValues++;
  585.     }
  586.     SetParsingFontCount(numFonts - num_fonts);
  587. }
  588.  
  589.  
  590. /* Add the list of scalable fonts to the match-list of every value instance
  591.  * for field f.  Must produce sorted order.  Must deal with duplicates
  592.  * since we need to do this for resolution fields which can be nonzero in
  593.  * the scalable fonts.
  594.  */
  595. void AddScalables(f)
  596.     int f;
  597. {
  598.     int i;
  599.     int max = fieldValues[f]->count;
  600.     FieldValue *fval = fieldValues[f]->value;
  601.  
  602.     for (i = 0; i < max; i++, fval++) {
  603.     int *oofonts, *ofonts, *nfonts, *fonts;
  604.     int ocount, ncount, count;
  605.  
  606.     if (fval->string && !strcmp(fval->string, "0"))
  607.         continue;
  608.     count = numScaledFonts;
  609.     fonts = scaledFonts;
  610.     ocount = fval->count;
  611.     ncount = ocount + count;
  612.     nfonts = (int *)XtMalloc( ncount * sizeof(int) );
  613.     oofonts = ofonts = fval->font;
  614.     fval->font = nfonts;
  615.     fval->count = ncount;
  616.     fval->allocated = ncount;
  617.     while (count && ocount) {
  618.         if (*fonts < *ofonts) {
  619.         *nfonts++ = *fonts++;
  620.         count--;
  621.         } else if (*fonts == *ofonts) {
  622.         *nfonts++ = *fonts++;
  623.         count--;
  624.         ofonts++;
  625.         ocount--;
  626.         fval->count--;
  627.         } else {
  628.         *nfonts++ = *ofonts++;
  629.         ocount--;
  630.         }
  631.     }
  632.     while (ocount) {
  633.         *nfonts++ = *ofonts++;
  634.         ocount--;
  635.     }
  636.     while (count) {
  637.         *nfonts++ = *fonts++;
  638.         count--;
  639.     }
  640.     XtFree((char *)oofonts);
  641.     }
  642. }
  643.  
  644.  
  645. /* Merge in specific scaled sizes (specified in a comma-separated string)
  646.  * for field f.  Weed out duplicates.  The set of matching fonts is just
  647.  * the set of scalable fonts.
  648.  */
  649. void NewScalables(f, slist)
  650.     int f;
  651.     char *slist;
  652. {
  653.     char endc = 1;
  654.     char *str;
  655.     int i, count;
  656.     FieldValue *v;
  657.  
  658.     while (endc) {
  659.     while (*slist == ' ' || *slist == ',')
  660.         slist++;
  661.     if (!*slist)
  662.         break;
  663.     str = slist;
  664.     while ((endc = *slist) && endc != ' ' && endc != ',')
  665.         slist++;
  666.     *slist++ = '\0';
  667.     for (i=fieldValues[f]->count,v=fieldValues[f]->value; --i >= 0; v++) {
  668.         if (v->string && !strcmp(v->string, str))
  669.         break;
  670.     }
  671.     if (i >= 0)
  672.         continue;
  673.     count = fieldValues[f]->count++;
  674.     if (count == fieldValues[f]->allocated) {
  675.         int allocated = (fieldValues[f]->allocated += 10);
  676.         fieldValues[f] = (FieldValueList*)
  677.         XtRealloc( (char *) fieldValues[f],
  678.                sizeof(FieldValueList) +
  679.                 (allocated-1) * sizeof(FieldValue) );
  680.     }
  681.     v = &fieldValues[f]->value[count];
  682.     v->field = f;
  683.     v->string = str;
  684.     v->count = numScaledFonts;
  685.     v->font = scaledFonts;
  686.     v->allocated = 0;
  687.     v->enable = True;
  688.     }
  689. }
  690.  
  691.  
  692. /* Find all scalable fonts, defined as the set matching "0" in the pixel
  693.  * size field (field 6).  Augment the match-lists for all other fields
  694.  * that are scalable.  Add in new scalable pixel and point sizes given
  695.  * in resources.
  696.  */
  697. /*ARGSUSED*/
  698. void FixScalables( closure )
  699.     XtPointer closure;
  700. {
  701.     int i;
  702.     FieldValue *fval = fieldValues[6]->value;
  703.  
  704.     for (i = fieldValues[6]->count; --i >= 0; fval++) {
  705.     if (fval->string && !strcmp(fval->string, "0")) {
  706.         scaledFonts = fval->font;
  707.         numScaledFonts = fval->count;
  708.         AddScalables(6);
  709.         NewScalables(6, AppRes.pixelSizeList);
  710.         AddScalables(7);
  711.         NewScalables(7, AppRes.pointSizeList);
  712.         AddScalables(8);
  713.         AddScalables(9);
  714.         AddScalables(11);
  715.         break;
  716.     }
  717.     }
  718. }
  719.  
  720.  
  721. /* Order is *, (nil), rest */
  722. int AlphabeticSort(fval1, fval2)
  723.     FieldValue *fval1, *fval2;
  724. {
  725.     if (fval1->string && !strcmp(fval1->string, "*"))
  726.     return -1;
  727.     if (fval2->string && !strcmp(fval2->string, "*"))
  728.     return 1;
  729.     if (!fval1->string)
  730.     return -1;
  731.     if (!fval2->string)
  732.     return 1;
  733.     return strcmp(fval1->string, fval2->string);
  734. }
  735.  
  736.  
  737. /* Order is *, (nil), rest */
  738. int NumericSort(fval1, fval2)
  739.     FieldValue *fval1, *fval2;
  740. {
  741.     if (fval1->string && !strcmp(fval1->string, "*"))
  742.     return -1;
  743.     if (fval2->string && !strcmp(fval2->string, "*"))
  744.     return 1;
  745.     if (!fval1->string)
  746.     return -1;
  747.     if (!fval2->string)
  748.     return 1;
  749.     return atoi(fval1->string) - atoi(fval2->string);
  750. }
  751.  
  752.  
  753. /* Resort each field, to get reasonable menus.  Sort alphabetically or
  754.  * numerically, depending on the field.  Since the fonts have indexes
  755.  * into the fields, we need to deal with updating those indexes after the
  756.  * sort.
  757.  */
  758. /*ARGSUSED*/
  759. void SortFields( closure )
  760.     XtPointer closure;
  761. {
  762.     int i, j, count;
  763.     FieldValue *vals;
  764.     int *indexes;
  765.     int *idx;
  766.  
  767.     for (i = 0; i < FIELD_COUNT; i++) {
  768.     count = fieldValues[i]->count;
  769.     vals = fieldValues[i]->value;
  770.     indexes = (int *)XtMalloc(count * sizeof(int));
  771.     /* temporarily use the field component, will restore it below */
  772.     for (j = 0; j < count; j++)
  773.         vals[j].field = j;
  774.     switch (i) {
  775.     case 6: case 7: case 8: case 9: case 11:
  776.         qsort((char *)vals, count, sizeof(FieldValue), NumericSort);
  777.         break;
  778.     default:
  779.         qsort((char *)vals, count, sizeof(FieldValue), AlphabeticSort);
  780.         break;
  781.     }
  782.     for (j = 0; j < count; j++) {
  783.         indexes[vals[j].field] = j;
  784.         vals[j].field = i;
  785.     }
  786.     for (j = 0; j < numFonts; j++) {
  787.         idx = &fonts[j].value_index[i];
  788.         if (*idx >= 0)
  789.         *idx = indexes[*idx];
  790.     }
  791.     XtFree((char *)indexes);
  792.     }
  793. }
  794.  
  795.  
  796. Boolean IsXLFDFontName(fontName)
  797.     String fontName;
  798. {
  799.     int f;
  800.     for (f = 0; *fontName;) if (*fontName++ == DELIM) f++;
  801.     return (f == FIELD_COUNT);
  802. }
  803.  
  804.  
  805. void MakeFieldMenu(closure)
  806.     XtPointer closure;
  807. {
  808.     FieldMenuRec *makeRec = (FieldMenuRec*)closure;
  809.     Widget menu;
  810.     FieldValueList *values = fieldValues[makeRec->field];
  811.     FieldValue *val = values->value;
  812.     int i;
  813.     Arg args[1];
  814.     register Widget item;
  815.  
  816.     if (numFonts)
  817.     menu =
  818.       XtCreatePopupShell("menu",simpleMenuWidgetClass,makeRec->button,NZ);
  819.     else {
  820.     SetNoFonts();
  821.     return;
  822.     }
  823.     XtGetSubresources(menu, (XtPointer) values, "options", "Options",
  824.               menuResources, XtNumber(menuResources), NZ);
  825.     XtAddCallback(menu, XtNpopupCallback, EnableOtherValues,
  826.           (XtPointer)makeRec->field );
  827.  
  828.     if (!patternFieldSpecified[val->field]) {
  829.     XtSetArg( args[0], XtNlabel, "*" );
  830.     item = XtCreateManagedWidget("any",smeBSBObjectClass,menu,args,ONE);
  831.     XtAddCallback(item, XtNcallback, AnyValue, (XtPointer)val->field);
  832.     }
  833.  
  834.     for (i = values->count; i; i--, val++) {
  835.     XtSetArg( args[0], XtNlabel, val->string ? val->string : "(nil)" );
  836.     item =
  837.         XtCreateManagedWidget(val->string ? val->string : "nil",
  838.                   smeBSBObjectClass, menu, args, ONE);
  839.     XtAddCallback(item, XtNcallback, SelectValue, (XtPointer)val);
  840.     val->menu_item = item;
  841.     }
  842. }
  843.  
  844.  
  845. SetNoFonts()
  846. {
  847.     matchingFontCount = 0;
  848.     SetCurrentFontCount();
  849.     XtSetSensitive(fieldBox, False);
  850.     XtSetSensitive(ownButton, False);
  851.     if (AppRes.app_defaults_version >= MIN_APP_DEFAULTS_VERSION) {
  852. #ifdef USE_TEXT_WIDGET
  853.     XtUnmapWidget(XtParent(sampleText));
  854. #else
  855.     XtUnmapWidget(sampleText);
  856. #endif
  857.     }
  858. }
  859.  
  860.  
  861. Boolean Matches(pattern, fontName, fields, maxField)
  862.     register String pattern, fontName;
  863.     Boolean fields[/*FIELD_COUNT*/];
  864.     int *maxField;
  865. {
  866.     register int field = (*fontName == DELIM) ? -1 : 0;
  867.     register Boolean marked_this_field = False;
  868.  
  869.     while (*pattern) {
  870.     if (*pattern == *fontName || *pattern == '?') {
  871.         pattern++;
  872.         if (*fontName++ == DELIM) {
  873.         field++;
  874.         marked_this_field = False;
  875.         }
  876.         else if (!marked_this_field)
  877.         fields[field] = marked_this_field = True; 
  878.         continue;
  879.     }
  880.     if (*pattern == '*') {
  881.         if (*++pattern == '\0') {
  882.         *maxField = field;
  883.         return True;
  884.         }
  885.         while (*fontName) {
  886.         Boolean field_bits[FIELD_COUNT];
  887.         int max_field;
  888.         if (*fontName == DELIM) field++;
  889.         bzero( field_bits, sizeof(field_bits) );
  890.         if (Matches(pattern, fontName++, field_bits, &max_field)) {
  891.             int f;
  892.             *maxField = field + max_field;
  893.             for (f = 0; f <= max_field; field++, f++)
  894.             fields[field] = field_bits[f];
  895.             return True;
  896.         }
  897.         }
  898.         return False;
  899.     }
  900.     else /* (*pattern != '*') */
  901.         return False;
  902.     }
  903.     if (*fontName)
  904.     return False;
  905.  
  906.     *maxField = field;
  907.     return True;
  908. }
  909.  
  910.  
  911. /* ARGSUSED */
  912. void SelectValue(w, closure, callData)
  913.     Widget w;
  914.     XtPointer closure, callData;
  915. {
  916.     FieldValue *val = (FieldValue*)closure;
  917. #ifdef LOG_CHOICES
  918.     Choice *choice = XtNew(Choice);
  919. #else
  920.     static Choice pChoice;
  921.     Choice *choice = &pChoice;
  922. #endif
  923.  
  924. #ifdef notdef
  925.     Widget button = XtParent(XtParent(w));
  926.     Arg args[1];
  927.  
  928.     XtSetArg(args[0], XtNlabel, val->string);
  929.     XtSetValues( button, args, ONE );
  930. #endif
  931.  
  932.     currentFont.value_index[val->field] = val - fieldValues[val->field]->value;
  933.  
  934.     choice->prev = choiceList;
  935.     choice->value = val;
  936.     choiceList = choice;
  937.     
  938.     SetCurrentFont(NULL);
  939.     EnableRemainingItems(SkipCurrentField);
  940. }
  941.  
  942.  
  943. /* ARGSUSED */
  944. void AnyValue(w, closure, callData)
  945.     Widget w;
  946.     XtPointer closure, callData;
  947. {
  948.     int field = (int)closure;
  949.     currentFont.value_index[field] = -1;
  950.     SetCurrentFont(NULL);
  951.     EnableAllItems(field);
  952.     EnableRemainingItems(ValidateCurrentField);
  953. }
  954.  
  955.  
  956. SetCurrentFontCount()
  957. {
  958.     char label[80];
  959.     Arg args[1];
  960.     if (matchingFontCount == 1)
  961.     strcpy( label, "1 name matches" );
  962.     else if (matchingFontCount)
  963.     sprintf( label, "%d names match", matchingFontCount );
  964.     else
  965.     strcpy( label, "no names match" );
  966.     XtSetArg( args[0], XtNlabel, label );
  967.     XtSetValues( countLabel, args, ONE );
  968. }
  969.  
  970.  
  971. SetParsingFontCount(count)
  972. {
  973.     char label[80];
  974.     Arg args[1];
  975.     if (count == 1)
  976.     strcpy( label, "1 name to parse" );
  977.     else
  978.     sprintf( label, "%d names to parse", count );
  979.     XtSetArg( args[0], XtNlabel, label );
  980.     XtSetValues( countLabel, args, ONE );
  981.     FlushXqueue(XtDisplay(countLabel));
  982. }
  983.  
  984.  
  985. /* ARGSUSED */
  986. void SetCurrentFont(closure)
  987.     XtPointer closure;        /* unused */
  988. {
  989.     int f;
  990.     Boolean *b;
  991.  
  992.     if (numFonts == 0) {
  993.     SetNoFonts();
  994.     return;
  995.     }
  996.     for (f = numFonts, b = fontInSet; f; f--, b++) *b = True;
  997.  
  998.     {
  999.     int bytesLeft = currentFontNameSize;
  1000.     int pos = 0;
  1001.  
  1002.     for (f = 0; f < FIELD_COUNT; f++) {
  1003.         int len, i;
  1004.         String str;
  1005.  
  1006.         currentFontNameString[pos++] = DELIM;
  1007.         if ((i = currentFont.value_index[f]) != -1) {
  1008.         FieldValue *val = &fieldValues[f]->value[i];
  1009.         if (str = val->string)
  1010.             len = strlen(str);
  1011.         else {
  1012.             str = "";
  1013.             len = 0;
  1014.         }
  1015.         MarkInvalidFonts(fontInSet, val);
  1016.         } else {
  1017.         str = "*";
  1018.         len = 1;
  1019.         }
  1020.         if (len+1 > --bytesLeft) {
  1021.         currentFontNameString = (String)
  1022.             XtRealloc(currentFontNameString, currentFontNameSize+=128);
  1023.         bytesLeft += 128;
  1024.         }
  1025.         strcpy( ¤tFontNameString[pos], str );
  1026.         pos += len;
  1027.         bytesLeft -= len;
  1028.     }
  1029.     }
  1030.     {
  1031.     Arg args[1];
  1032.     XtSetArg( args[0], XtNlabel, currentFontNameString );
  1033.     XtSetValues( currentFontName, args, ONE );
  1034.     }
  1035.     matchingFontCount = 0;
  1036.     for (f = numFonts, b = fontInSet; f; f--, b++) {
  1037.     if (*b) matchingFontCount++;
  1038.     }
  1039.  
  1040.     SetCurrentFontCount();
  1041.  
  1042.     {
  1043. #ifdef USE_TEXT_WIDGET
  1044.     Widget mapWidget = XtParent(sampleText);
  1045. #else
  1046.     Widget mapWidget = sampleText;
  1047. #endif
  1048.     Display *dpy = XtDisplay(mapWidget);
  1049.     XFontStruct *font = XLoadQueryFont(dpy, currentFontNameString);
  1050.     if (font == NULL)
  1051.         XtUnmapWidget(mapWidget);
  1052.     else {
  1053.         int nargs = 1;
  1054.         Arg args[3];
  1055.         int encoding;
  1056.         if (font->min_byte1 || font->max_byte1)
  1057.         encoding = XawTextEncodingChar2b;
  1058.         else
  1059.         encoding = XawTextEncoding8bit;
  1060.         XtSetArg( args[0], XtNfont, font );
  1061.         if (encoding != textEncoding) {
  1062.         XtSetArg(args[1], XtNencoding, encoding);
  1063.         XtSetArg(args[2], XtNlabel,
  1064.              encoding == XawTextEncodingChar2b
  1065.              ? AppRes.sample_text16 : AppRes.sample_text);
  1066.         textEncoding = encoding;
  1067.         nargs = 3;
  1068.         }
  1069.         XtSetValues( sampleText, args, nargs );
  1070.         XtMapWidget(mapWidget);
  1071.         if (sampleFont) XFreeFont( dpy, sampleFont );
  1072.         sampleFont = font;
  1073.         OwnSelection( sampleText, (XtPointer)False, (XtPointer)True );
  1074.     }
  1075.     FlushXqueue(dpy);
  1076.     }
  1077. }
  1078.  
  1079.  
  1080. MarkInvalidFonts( set, val )
  1081.     Boolean *set;
  1082.     FieldValue *val;
  1083. {
  1084.     int fi = 0, vi;
  1085.     int *fp = val->font;
  1086.     for (vi = val->count; vi; vi--, fp++) {
  1087.     while (fi < *fp) {
  1088.         set[fi] = False;
  1089.         fi++;
  1090.     }
  1091.     fi++;
  1092.     }
  1093.     while (fi < numFonts) {
  1094.     set[fi] = False;
  1095.     fi++;
  1096.     }
  1097. }
  1098.  
  1099.  
  1100. EnableRemainingItems(current_field_action)
  1101.     ValidateAction current_field_action;
  1102. {
  1103.     if (matchingFontCount == 0 || matchingFontCount == numFonts) {
  1104.     if (anyDisabled) {
  1105.         int field;
  1106.         for (field = 0; field < FIELD_COUNT; field++) {
  1107.         EnableAllItems(field);
  1108.         }
  1109.         anyDisabled = False;
  1110.     }
  1111.     }
  1112.     else {
  1113.     int field;
  1114.     for (field = 0; field < FIELD_COUNT; field++) {
  1115.         FieldValue *value = fieldValues[field]->value;
  1116.         int count;
  1117.         if (current_field_action == SkipCurrentField &&
  1118.         field == choiceList->value->field)
  1119.         continue;
  1120.         for (count = fieldValues[field]->count; count; count--, value++) {
  1121.         int *fp = value->font;
  1122.         int fontCount;
  1123.         for (fontCount = value->count; fontCount; fontCount--, fp++) {
  1124.             if (fontInSet[*fp]) {
  1125.             value->enable = True;
  1126.             goto NextValue;
  1127.             }
  1128.         }
  1129.         value->enable = False;
  1130.           NextValue:;
  1131.         }
  1132.     }
  1133.     anyDisabled = True;
  1134.     }
  1135.     enabledMenuIndex = -1;
  1136.     {
  1137.     int f;
  1138.     for (f = 0; f < FIELD_COUNT; f++)
  1139.         ScheduleWork(EnableMenu, (XtPointer)f, BACKGROUND);
  1140.     }
  1141. }
  1142.  
  1143.  
  1144. EnableAllItems(field)
  1145. {
  1146.     FieldValue *value = fieldValues[field]->value;
  1147.     int count;
  1148.     for (count = fieldValues[field]->count; count; count--, value++) {
  1149.     value->enable = True;
  1150.     }
  1151. }
  1152.  
  1153.  
  1154. /* ARGSUSED */
  1155. void SelectField(w, closure, callData)
  1156.     Widget w;
  1157.     XtPointer closure, callData;
  1158. {
  1159.     int field = (int)closure;
  1160.     FieldValue *values = fieldValues[field]->value;
  1161.     int count = fieldValues[field]->count;
  1162.     printf( "field %d:\n", field );
  1163.     while (count--) {
  1164.     printf( " %s: %d fonts\n", values->string, values->count );
  1165.     values++;
  1166.     }
  1167.     printf( "\n" );
  1168. }
  1169.  
  1170.  
  1171. /* When 2 out of 3 y-related scalable fields are set, we need to restrict
  1172.  * the third set to only match on exact matches, that is, ignore the
  1173.  * matching to scalable fonts.  Because choosing a random third value
  1174.  * will almost always produce an illegal font name, and it isn't worth
  1175.  * trying to compute which choices might be legal to the font scaler.
  1176.  */
  1177. void DisableScaled(f, f1, f2)
  1178.     int f, f1, f2;
  1179. {
  1180.     int i, j;
  1181.     FieldValue *v;
  1182.     int *font;
  1183.     char *str;
  1184.  
  1185.     for (i = fieldValues[f]->count, v = fieldValues[f]->value; --i >= 0; v++) {
  1186.     if (!v->enable || !v->string || !strcmp(v->string, "0"))
  1187.         continue;
  1188.     for (j = v->count, font = v->font; --j >= 0; font++) {
  1189.         if (fontInSet[*font] &&
  1190.         fonts[*font].value_index[f1] == currentFont.value_index[f1] &&
  1191.         fonts[*font].value_index[f2] == currentFont.value_index[f2])
  1192.         break;
  1193.     }
  1194.     if (j < 0) {
  1195.         v->enable = False;
  1196.         XtSetSensitive(v->menu_item, False);
  1197.     }
  1198.     }
  1199. }
  1200.  
  1201. /* ARGSUSED */
  1202. void EnableOtherValues(w, closure, callData)
  1203.     Widget w;
  1204.     XtPointer closure, callData;
  1205. {
  1206.     int field = (int)closure;
  1207.     Boolean *font_in_set = (Boolean*)XtMalloc(numFonts*sizeof(Boolean));
  1208.     Boolean *b;
  1209.     int f, count;
  1210.  
  1211.     FinishWork();
  1212.     for (f = numFonts, b = font_in_set; f; f--, b++) *b = True;
  1213.     for (f = 0; f < FIELD_COUNT; f++) {
  1214.     int i;
  1215.     if (f != field && (i = currentFont.value_index[f]) != -1) {
  1216.         MarkInvalidFonts( font_in_set, &fieldValues[f]->value[i] );
  1217.     }
  1218.     }
  1219.     if (scaledFonts)
  1220.     {
  1221.     /* Check for 2 out of 3 scalable y fields being set */
  1222.     char *str;
  1223.     Bool specificPxl, specificPt, specificY;
  1224.  
  1225.     f = currentFont.value_index[6];
  1226.     specificPxl = (f >= 0 &&
  1227.                (str = fieldValues[6]->value[f].string) &&
  1228.                strcmp(str, "0"));
  1229.     f = currentFont.value_index[7];
  1230.     specificPt = (f >= 0 &&
  1231.               (str = fieldValues[7]->value[f].string) &&
  1232.               strcmp(str, "0"));
  1233.     f = currentFont.value_index[9];
  1234.     specificY = (f >= 0 &&
  1235.              (str = fieldValues[9]->value[f].string) &&
  1236.              strcmp(str, "0"));
  1237.     if (specificPt && specificY)
  1238.         DisableScaled(6, 7, 9);
  1239.     if (specificPxl && specificY)
  1240.         DisableScaled(7, 6, 9);
  1241.     if (specificPxl && specificPt)
  1242.         DisableScaled(9, 6, 7);
  1243.     }
  1244.     count = 0;
  1245.     for (f = numFonts, b = font_in_set; f; f--, b++) {
  1246.     if (*b) count++;
  1247.     }
  1248.     if (count != matchingFontCount) {
  1249.     Boolean *sp = fontInSet;
  1250.     FieldValueList *fieldValue = fieldValues[field];
  1251.     for (b = font_in_set, f = 0; f < numFonts; f++, b++, sp++) {
  1252.         if (*b != *sp) {
  1253.         int i = fonts[f].value_index[field];
  1254.         FieldValue *val = &fieldValue->value[i];
  1255.         val->enable = True;
  1256.         XtSetSensitive(val->menu_item, True);
  1257.         if (++count == matchingFontCount) break;
  1258.         }
  1259.     }
  1260.     }
  1261.     XtFree((char *)font_in_set);
  1262.     if (enabledMenuIndex < field)
  1263.     EnableMenu((XtPointer)field);
  1264. }
  1265.  
  1266.  
  1267. void EnableMenu(closure)
  1268.     XtPointer closure;
  1269. {
  1270.     int field = (int)closure;
  1271.     FieldValue *val = fieldValues[field]->value;
  1272.     int f;
  1273.     Widget *managed = NULL, *pManaged = NULL;
  1274.     Widget *unmanaged = NULL, *pUnmanaged = NULL;
  1275.     Boolean showUnselectable = fieldValues[field]->show_unselectable;
  1276.  
  1277.     for (f = fieldValues[field]->count; f; f--, val++) {
  1278.     if (showUnselectable) {
  1279.         if (val->enable != XtIsSensitive(val->menu_item))
  1280.         XtSetSensitive(val->menu_item, val->enable);
  1281.     }
  1282.     else {
  1283.         if (val->enable != XtIsManaged(val->menu_item)) {
  1284.         if (val->enable) {
  1285.             if (managed == NULL) {
  1286.             managed = (Widget*)
  1287.                 XtMalloc(fieldValues[field]->count*sizeof(Widget));
  1288.             pManaged = managed;
  1289.             }
  1290.             *pManaged++ = val->menu_item;
  1291.         }
  1292.         else {
  1293.             if (unmanaged == NULL) {
  1294.             unmanaged = (Widget*)
  1295.                 XtMalloc(fieldValues[field]->count*sizeof(Widget));
  1296.             pUnmanaged = unmanaged;
  1297.             }
  1298.             *pUnmanaged++ = val->menu_item;
  1299.         }
  1300.         }
  1301.     }
  1302.     }
  1303.     if (pManaged != managed) {
  1304.     XtManageChildren(managed, pManaged - managed);
  1305.     XtFree((char *) managed);
  1306.     }
  1307.     if (pUnmanaged != unmanaged) {
  1308.     XtUnmanageChildren(unmanaged, pUnmanaged - unmanaged);
  1309.     XtFree((char *) unmanaged);
  1310.     }
  1311.     enabledMenuIndex = field;
  1312. }
  1313.  
  1314.  
  1315. FlushXqueue(dpy)
  1316.     Display *dpy;
  1317. {
  1318.     XSync(dpy, False);
  1319.     while (XtAppPending(appCtx)) XtAppProcessEvent(appCtx, XtIMAll);
  1320. }
  1321.  
  1322.  
  1323. /* ARGSUSED */
  1324. void Quit(w, closure, callData)
  1325.     Widget w;
  1326.     XtPointer closure, callData;
  1327. {
  1328.     XtCloseDisplay(XtDisplay(w));
  1329.     if (AppRes.print_on_quit) printf( "%s", currentFontNameString );
  1330.     exit(0);
  1331. }
  1332.  
  1333.  
  1334. Boolean ConvertSelection(w, selection, target, type, value, length, format)
  1335.     Widget w;
  1336.     Atom *selection, *target, *type;
  1337.     XtPointer *value;
  1338.     unsigned long *length;
  1339.     int *format;
  1340. {
  1341.     /* XmuConvertStandardSelection will use the second parameter only when
  1342.      * converting to the target TIMESTAMP.  However, it will never be
  1343.      * called upon to perform this conversion, because Xt will handle it
  1344.      * internally.  CurrentTime will never be used.
  1345.      */
  1346.     if (XmuConvertStandardSelection(w, CurrentTime, selection, target, type,
  1347.                     (caddr_t *) value, length, format))
  1348.     return True;
  1349.  
  1350.     if (*target == XA_STRING) {
  1351.     *type = XA_STRING;
  1352.     *value = currentFontNameString;
  1353.     *length = strlen(*value);
  1354.     *format = 8;
  1355.     return True;
  1356.     }
  1357.     else {
  1358.     return False;
  1359.     }
  1360. }
  1361.  
  1362. static AtomPtr _XA_PRIMARY_FONT = NULL;
  1363. #define XA_PRIMARY_FONT XmuInternAtom(XtDisplay(w),_XA_PRIMARY_FONT)
  1364.  
  1365. /* ARGSUSED */
  1366. void LoseSelection(w, selection)
  1367.     Widget w;
  1368.     Atom *selection;
  1369. {
  1370.     Arg args[1];
  1371.     XtSetArg( args[0], XtNstate, False );
  1372.     XtSetValues( w, args, ONE );
  1373.     if (*selection == XA_PRIMARY_FONT) {
  1374.     XtSetSensitive(currentFontName, False);
  1375.     }
  1376. }
  1377.  
  1378.  
  1379. /* ARGSUSED */
  1380. void DoneSelection(w, selection, target)
  1381.     Widget w;
  1382.     Atom *selection, *target;
  1383. {
  1384.     /* do nothing */
  1385. }
  1386.  
  1387.  
  1388. /* ARGSUSED */
  1389. void OwnSelection(w, closure, callData)
  1390.     Widget w;
  1391.     XtPointer closure, callData;
  1392. {
  1393.     Time time = XtLastTimestampProcessed(XtDisplay(w));
  1394.     Boolean primary = (Boolean) (int) closure;
  1395.     Boolean own = (Boolean) (int) callData;
  1396.  
  1397.     if (_XA_PRIMARY_FONT == NULL)
  1398.     _XA_PRIMARY_FONT = XmuMakeAtom("PRIMARY_FONT");
  1399.  
  1400.     if (own) {
  1401.     XtOwnSelection( w, XA_PRIMARY_FONT, time,
  1402.             ConvertSelection, LoseSelection, DoneSelection );
  1403.     if (primary)
  1404.         XtOwnSelection( w, XA_PRIMARY, time,
  1405.                ConvertSelection, LoseSelection, DoneSelection );
  1406.     if (!XtIsSensitive(currentFontName)) {
  1407.         XtSetSensitive(currentFontName, True);
  1408.     }
  1409.     }
  1410.     else {
  1411.     XtDisownSelection(w, XA_PRIMARY_FONT, time);
  1412.     if (primary)
  1413.         XtDisownSelection(w, XA_PRIMARY, time);
  1414.     XtSetSensitive(currentFontName, False);
  1415.     }
  1416. }
  1417.  
  1418. void
  1419. QuitAction ()
  1420. {
  1421.     exit (0);
  1422. }
  1423.